package utils;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import meadow.Meadow;
import uk.ac.nott.cs.g53dia.Cell;
import uk.ac.nott.cs.g53dia.Flower;
import uk.ac.nott.cs.g53dia.Point;
import uk.ac.nott.cs.g53dia.UnseenCell;
import valueobj.IndexPair;

public class General {

  public static Cell[][] deepCopy(Object[][] arg) {
    Cell[][] returnVal = new Cell[arg.length][arg[0].length];
    for (int i = 0; i < arg.length; i++) {
      for (int j = 0; j < arg[0].length; j++) {
        returnVal[i][j] = (Cell) ((Cell) arg[i][j]).clone();
      }
    }
    return returnVal;
  }

  public static int distance(Point p1, Point p2) {
    return Math.max(Math.abs(p2.x - p1.x), Math.abs(p2.y - p1.y));
  }

  public static IndexPair getIndexPairForMeadow(Point point) {
    return new IndexPair(Meadow.columns / 2 + point.x, Meadow.rows / 2 - point.y);
  }

  public static Point getPointForMeadow(IndexPair pair) {
    return new Point(pair.getX() - Meadow.columns / 2, Meadow.rows / 2 - pair.getY());
  }

  // public static IndexPair getIndexPairForBee(Point point) {
  // return new IndexPair(Meadow.columns / 2 + point.x, Meadow.rows / 2
  // - point.y);
  // }

  public static float sumFloats(float[] floats, float[] weights) {
    if (floats == null) {
      throw new NullPointerException("argument float[] floats");
    }
    float sum = 0f;
    for (int i = 0; i < Flower.NUM_TYPES; i++) {
      sum += weights[i] * floats[i];
    }
    return sum;
  }

  public static float sumFloats(float[] floats) {
    return sumFloats(floats, new float[] {1,1,1,1,1});
  }
  
  public static float sumFloats(Float[] floats) {
    float[] array = new float[floats.length];
    for (int i = 0; i < floats.length; i++) {
      array[i] = floats[i];
    }
    return sumFloats(array, new float[] {1,1,1,1,1});
  }

  public static int rouletteWheel(List<? extends Number> distribution) {
    if (distribution == null || distribution.size() == 0) {
      throw new IllegalArgumentException("argument distribution is empty");
    }
    if (distribution.size() == 1) return 0;
    float sum = 0f;
    for (int i = 0; i < distribution.size(); i++) {
      sum += distribution.get(i).floatValue();
    }
    float roulette = RandomGenerator.getRandomFloat();
    float test = 0f;
    for (int i = 0; i < distribution.size(); i++) {
      if (sum < Constants.PREC) {
        test = (float) (i + 1) / distribution.size(); // normal distr.
      } else {
        test += distribution.get(i).floatValue() / sum;
      }
      if (test >= roulette) {
        return i;
      }
    }
    throw new IllegalStateException("rouletteWheel failed");
  }
  
  public static int powerRoulette(List<? extends Number> distribution) {
    if (distribution == null || distribution.size() == 0) {
      throw new IllegalArgumentException("argument distribution is empty");
    }
    if (distribution.size() == 1) return 0;
    List<Float> result = new ArrayList<Float>(distribution.size());
    for (int i = 0; i < distribution.size(); i++) {
        result.add(distribution.get(i).floatValue() * distribution.get(i).floatValue());
      
    }
    return rouletteWheel(result);
  }
  
  public static int winnerTakesAll(List<? extends Number> distribution) {
    if (distribution == null || distribution.size() == 0) {
      throw new IllegalArgumentException("argument distribution is empty");
    }
    if (distribution.size() == 1) return 0;
    Number max = -1;
    int index = -1;
    for (int i = 0; i < distribution.size(); i++) {
      if (max.floatValue() < distribution.get(i).floatValue()){
        max = distribution.get(i);
        index = i;
      }
    }
    return index;
  }

  public static String floatsToString(float[] floats) {
    if (floats == null || floats.length != Flower.NUM_TYPES + 1) {
      throw new IllegalArgumentException("argument float[] floats");
    }
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < Flower.NUM_TYPES; i++) {
      result.append("  Flower of type " + i + " = " + floats[i]);
    }
    return result.toString();
  }

  public static Color getShade(Color original, int number) {
    int red = original.getRed() * (Flower.MAX_FLOWERS_IN_CLUMP - number) / Flower.MAX_FLOWERS_IN_CLUMP;
    int green = original.getGreen() * (Flower.MAX_FLOWERS_IN_CLUMP - number) / Flower.MAX_FLOWERS_IN_CLUMP;
    int blue = original.getBlue() * (Flower.MAX_FLOWERS_IN_CLUMP - number) / Flower.MAX_FLOWERS_IN_CLUMP;

    return new Color(red, green, blue);
  }

  public static boolean areAllFlowersPresent(float[] floats) {
    if (floats == null || floats.length != Flower.NUM_TYPES + 1) {
      throw new IllegalArgumentException("argument float[] floats");
    }
    return floats[0] > Constants.PREC && floats[1] > Constants.PREC && floats[2] > Constants.PREC
        && floats[3] > Constants.PREC && floats[4] > Constants.PREC;
  }

  public static void complementToRectangle(Map<Point, Cell> cells) {
    if (cells == null || cells.size() == 0) {
      throw new IllegalArgumentException();
    }
    List<Point> knownPoints = new ArrayList<Point>(cells.keySet());
    int minX, maxX, minY, maxY;
    Collections.sort(knownPoints, ComparatorFactory.getPointXComparator());
    minX = knownPoints.get(0).x;
    maxX = knownPoints.get(knownPoints.size() - 1).x;
    Collections.sort(knownPoints, ComparatorFactory.getPointYComparator());
    minY = knownPoints.get(0).y;
    maxY = knownPoints.get(knownPoints.size() - 1).y;
    for (int i = minX; i <= maxX; i++) {
      for (int j = minY; j <= maxY; j++) {
        if (!cells.keySet().contains(new Point(i, j))) {
          cells.put(new Point(i, j), new UnseenCell(new Point(i, j)));
        }
      }
    }
  }

}
